perm filename ARITH2.2[EAL,HE]1 blob sn#674767 filedate 1982-09-27 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00008 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	(*$NOMAIN	More arithmetic routines used by AL *)
C00003 00003	(* Externally defined routines *)
C00005 00004	(* trig functions: asin, acos & atan2 *)
C00007 00005	(* Misc. vector function: vmake *)
C00008 00006	(* trans extraction routines: taxis, tmagn, tpos, torient *)
C00013 00007	(* trans functions: tmake, tvadd, tvsub, ttmul, tinvrt *)
C00017 00008	(* Aux routines just to calculate Exp & Log *)
C00018 ENDMK
C⊗;
(*$NOMAIN	More arithmetic routines used by AL *)

program arith2;

const pi = 3.1415926535; rad = 0.0174532925;

type scalar = real;
     ascii = char;
     vectorval = array [1..3] of real;
     vector = record  refcnt: integer; val: vectorval end;
     vectorp = ↑vector;
     transval = array [1..3,1..4] of real;
     trans = record  refcnt: integer; val: transval end;
     transp = ↑trans;

cstring = packed array [1..10] of ascii;
c5str = packed array [1..5] of ascii;
c20str = packed array [1..20] of ascii;

(* Externally defined routines *)

	(* From ALLOC *)
function newVector: vectorp;					external;
procedure relVector(v: vectorp);				external;
function newTrans: transp;					external;
procedure relTrans(t: transp);					external;

	(* Display-related Routines *)
procedure ppLine; 						external;
procedure ppOutNow; 						external;
procedure ppChar(ch: ascii); 					external;
procedure pp5(ch: c5str; length: integer); 			external;
procedure pp10(ch: cstring; length: integer); 			external;
procedure pp10L(ch: cstring; length: integer);			external;
procedure pp20(ch: c20str; length: integer); 			external;
procedure pp20L(ch: c20str; length: integer); 			external;
procedure ppInt(i: integer); 					external;
procedure ppReal(r: real); 					external;

(* trig functions: asin, acos & atan2 *)

function asin(x: real): real; external;
function asin;
 begin
 if x = 1.0 then asin := 90.0
  else asin := arctan(x/sqrt(1.0-x*x))/rad;
 end;

function acos(x: real): real; external;
function acos;
 var s: real;
 begin
 if x = 0.0 then acos := 90.0
  else
   begin
   s := arctan(sqrt(1.0-x*x)/x)/rad;
   if x < 0 then acos := 180.0 + s else acos := s;
   end;
 end;

function atan2(y,x: real): real; external; 	(* 4-quadrant arctan(y/x) *) 
function atan2;
 var ans: real;
 begin 
 if x = 0.0 then
   begin
   if y = 0.0 then ans := 0.0		(* Actually indeterminate, but ... *)
    else if y > 0.0 then ans := 90.0
    else ans := -90.0;
   end
  else
   begin 
   ans := arctan(y/x)/rad;
   if x < 0 then 
    if y < 0 then ans := ans - 180.0
     else ans := ans + 180.0;
   end;
 atan2 := ans;
 end;


(* Misc. vector function: vmake *)

function vmake (a,b,c: scalar): vectorp; external;
function vmake ;
var v: vectorp;
begin
 v := newVector;
 with v↑ do begin val[1] := a; val[2] := b; val[3] := c; end;
 vmake := v;
end;

(* trans extraction routines: taxis, tmagn, tpos, torient *)

function ssqrt(v: real): real; external;
function ssqrt;
 begin if (-0.000001 < v) and (v < 0) then ssqrt:= 0.0 else ssqrt:= sqrt(v) end;

function taxis (t: transp): vectorp; external;
function taxis ;
 (* extracts the axis of rotation from a trans *)
var cx,cy,cz,a,b,c,d,cw: real; temp:real;
begin
 a := t↑.val[1,1];
 b := t↑.val[2,2];
 c := t↑.val[3,3];
 cw := (a+b+c-1)/2;
 if cw > 0.9999 then taxis := vmake(0,0,1)	(* vector for nilrot = zhat *)
 else		
  with t↑ do
   begin
    d := 3-a-b-c;
    cz := ssqrt((-a-b+c+1)/d);
    if cz < 0.001 then cy := ssqrt((-a+b-c+1)/d)
     else begin cy := (val[3,2] - val[1,2]*val[3,1] / (a-1)) * cz ;
		temp := val[1,2] * val[2,1] / (a-1);	{ For OMSI's sake }
		cy := cy / (1 - b + temp); end;
    if cz+abs(cy) < 0.001 then cx := ssqrt((a-b-c+1)/d)
     else cx := -(val[2,1]*cy + val[3,1]*cz) / (a-1);
    taxis := vmake(cx,cy,cz);	
   end;
 if t↑.refcnt <= 0 then relTrans(t);
end;

function tmagn (t: transp): scalar; external;
function tmagn ;
 (* finds the angle of rotation in a trans *)
var cx,cy,cz,a,b,c,d,cw,s: real; temp:real;
begin
 with t↑ do
  begin
   a := val[1,1];
   b := val[2,2];
   c := val[3,3];
   cw := (a+b+c-1)/2;
   if cw > 0.9999 then tmagn := 0		(* angle for nilrot *)
    else
     begin
     d := 3-a-b-c;
     cz := ssqrt((-a-b+c+1)/d);
     if cz < 0.001 then cy := ssqrt((-a+b-c+1)/d)
      else begin cy := (val[3,2] - val[1,2]*val[3,1] / (a-1)) * cz ;
		 temp := val[1,2] * val[2,1] / (a-1);	{ For OMSI's sake }
		 cy := cy / (1 - b + temp); end;
     if cz+abs(cy) < 0.001 then cx := ssqrt((a-b-c+1)/d)
      else cx := -(val[2,1]*cy + val[3,1]*cz) / (a-1);
     if (-1.000001 < cw) and (cw < -1.0) then s := 180
      else if (1.0000 < cw) and (cw < 1.000001) then s := 0
      else s := acos(cw);
     if abs(cz) >= 0.577 then
	begin if (val[1,2]-val[2,1])/cz > 0 then s := -s end
     else if abs(cy) >= 0.577 then
	begin if (val[3,1]-val[1,3])/cy > 0 then s := -s end
     else if abs(cx) >= 0.577 then
	begin if (val[2,3]-val[3,2])/cx > 0 then s := -s end
     else
	begin
	pp20L('tmagn: rotation stra',20); pp10('ngeness!  ',8); ppLine;
	end;
     tmagn := s;
     end;
   if refcnt <= 0 then relTrans(t);
  end;
end;

function tpos (t: transp): vectorp; external;
function tpos ;
var v: vectorp; i: 1..3;
begin
 v := newVector;
 with t↑ do for i:= 1 to 3 do v↑.val[i] := val[i,4];
 if t↑.refcnt <= 0 then relTrans(t);
 tpos := v;
end;

function torient (t: transp): transp; external;
function torient ;
var r: transp; i,j: 1..3;
begin
 r := newTrans;
 with t↑ do
  for i := 1 to 3 do
   begin
   for j := 1 to 3 do r↑.val[i,j] := val[i,j];
   r↑.val[i,4] := 0;
   end;
 if t↑.refcnt <= 0 then relTrans(t);
 torient := r;
end;

(* trans functions: tmake, tvadd, tvsub, ttmul, tinvrt *)

procedure tcopy(var tp,t: transval); external;	(* auxiliary routine *) 
procedure tcopy;
var i,j: 1..4;
begin for i := 1 to 3 do for j := 1 to 4 do tp[i,j] := t[i,j]; end;

function tmake (t: transp; v: vectorp): transp; external;
function tmake ;
var tp: transp; i: 1..3;
begin
 if t↑.refcnt <= 0 then tp := t
  else begin tp := newTrans; tcopy(tp↑.val,t↑.val); end; (* copy rotation part *)
 with tp↑ do
  for i := 1 to 3 do val[i,4] := v↑.val[i];	(* and vector part *)
 if v↑.refcnt <= 0 then relVector(v);
 tmake := tp;
end;

function tvadd (t: transp; v: vectorp): transp; external;
function tvadd ;
var tp: transp; i,j: 1..3;
begin
 if t↑.refcnt <= 0 then tp := t
  else begin tp := newTrans; tcopy(tp↑.val,t↑.val); end; (* copy rotation part *)
 with tp↑ do
  for i := 1 to 3 do val[i,4] := val[i,4] + v↑.val[i];	(* add in vector *)
 if v↑.refcnt <= 0 then relVector(v);
 tvadd := tp;
end;

function tvsub (t: transp; v: vectorp): transp; external;
function tvsub ;
var tp: transp; i,j: 1..3;
begin
 if t↑.refcnt <= 0 then tp := t
  else begin tp := newTrans; tcopy(tp↑.val,t↑.val); end; (* copy rotation part *)
 with tp↑ do
  for i := 1 to 3 do val[i,4] := val[i,4] - v↑.val[i];	(* subtract vector *)
 if v↑.refcnt <= 0 then relVector(v);
 tvsub := tp;
end;

function ttmul (t1,t2: transp): transp; external;
function ttmul ;
var tp: transp; i,j,k: 1..4;
begin
 tp := newTrans;
 with tp↑ do
  for i := 1 to 3 do
   begin
   for j := 1 to 4 do			(* rotate t2 by orient(t1) *)
    begin
    val[i,j] := 0;
    for k := 1 to 3 do val[i,j] := val[i,j] + t1↑.val[i,k]*t2↑.val[k,j];
    end;
   val[i,4] := val[i,4] + t1↑.val[i,4];	(* add in t1 vector offset *)
   end;
 if t1↑.refcnt <= 0 then relTrans(t1);
 if t2↑.refcnt <= 0 then relTrans(t2);
 ttmul := tp;
end;

function tinvrt (t: transp): transp; external;
function tinvrt ;
var tp: transp; i,j,k: 1..4;
begin	(* The result, (rot',trslat'), is defined: rot' = transpose(rot)
						trslat' = -(rot'*trslat) *)
 tp := newTrans;
 with tp↑ do
  for i := 1 to 3 do
   begin
   val[i,4] := 0;
   for j := 1 to 3 do
    begin
    val[i,j] := t↑.val[j,i];			(* transpose rotation part *)
    val[i,4] := val[i,4] - t↑.val[j,i] * t↑.val[j,4];	(* build up new vector offset *)
    end;
   end;
 if t↑.refcnt <= 0 then relTrans(t);
 tinvrt := tp;
end;

(* Aux routines just to calculate Exp & Log *)

function auxExp(s:real): real; external;
function auxExp;
  begin auxExp := exp(s) end;

function auxLn(s:real): real; external;
function auxLn;
  begin auxLn := ln(s) end;